//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"

// defined client class method declarations for addref and release.
#ifndef FC_ADDREF_METHOD_DECL
#define FC_ADDREF_METHOD_DECL		AddRef
#endif
#ifndef FC_RELEASEREF_METHOD_DECL
#define FC_RELEASEREF_METHOD_DECL	ReleaseRef
#endif

FC_NAMESPACE_BEGIN


template<class T>
class intrusive_ptr
{
public:
	typedef T						element_type;
	typedef intrusive_ptr<T>		this_type;

	intrusive_ptr() : _ptr(0) {}
	intrusive_ptr( T* ptr, bool addRef = true )
		: _ptr(ptr)
		{
			if(ptr && addRef)
				ptr->FC_ADDREF_METHOD_DECL();
		}

	intrusive_ptr( const this_type& p ) : _ptr(p._ptr)
		{
			if(_ptr)
				_ptr->FC_ADDREF_METHOD_DECL();
		}

	template<class U>
	intrusive_ptr( const intrusive_ptr<U>& p ) : _ptr(p._ptr)
		{
			if(_ptr)
				_ptr->FC_ADDREF_METHOD_DECL();
		}

	~intrusive_ptr()
		{
			if(_ptr)
				_ptr->FC_RELEASEREF_METHOD_DECL();
		}

	operator bool() const	{ return _ptr != 0; }
	T& operator*() const	{ FC_ASSERT(_ptr); return *_ptr; }
	T* operator->() const	{ FC_ASSERT(_ptr); return _ptr; }
	T* get() const			{ return _ptr; }

	void add_ref()
	{
		if(_ptr)
			_ptr->FC_ADDREF_METHOD_DECL();
	}

	void release()
	{
		if(_ptr)
			_ptr->FC_RELEASEREF_METHOD_DECL();
	}

	void reset( T* ptr = 0 )
	{
		if(_ptr)
			_ptr->FC_RELEASEREF_METHOD_DECL();

		_ptr = ptr;
		if(_ptr)
			_ptr->FC_ADDREF_METHOD_DECL();
	}

	this_type& operator =( const this_type& p )
	{
		reset(p._ptr);
		return *this;
	}

	template<class U>
	this_type& operator =( const intrusive_ptr<U>& p )
	{
		reset((T*)p._ptr);
		return *this;
	}

	this_type& operator =( T* ptr )
	{
		reset(ptr);
		return *this;
	}

	void swap( this_type & p )
	{
		fc::swap(_ptr, p._ptr);
	}

protected:
	T* _ptr;

};


template<class T, class U> inline
bool operator ==( const intrusive_ptr<T>& a, const intrusive_ptr<U>& b )
{
	return a.get() == b.get();
}

template<class T, class U> inline
bool operator !=( const intrusive_ptr<T>& a, const intrusive_ptr<U>& b )
{
	return a.get() != b.get();
}

template<class T, class U> inline
bool operator ==( const intrusive_ptr<T>& a, U* b )
{
	return a.get() == b;
}

template<class T, class U> inline
bool operator !=( const intrusive_ptr<T>& a, U* b )
{
	return a.get() != b;
}

template<class T, class U> inline
bool operator ==( T* a, const intrusive_ptr<U>& b )
{
	return a == b.get();
}

template<class T, class U> inline
bool operator !=( T* a, const intrusive_ptr<U>& b )
{
	return a != b.get();
}

template<class T> inline
bool operator <( const intrusive_ptr<T>& a, const intrusive_ptr<T>& b )
{
	return a.get() < b.get();
}



FC_NAMESPACE_END

